package com.gmrz.uaf.remote.protocol.v1.processor;

import com.gmrz.uaf.common.GuiceUtil;
import com.gmrz.uaf.db.DAOException;
import com.gmrz.uaf.protocol.v1.json.UAFSchemaBuilder;
import com.gmrz.uaf.protocol.v1.processor.UAFRegInitProcessor;
import com.gmrz.uaf.protocol.v1.processor.exception.AuthenticationFailedException;
import com.gmrz.uaf.protocol.v1.processor.exception.PolicyNotFoundException;
import com.gmrz.uaf.protocol.v1.processor.exception.UAFErrorCode;
import com.gmrz.uaf.protocol.v1.schema.Extension;
import com.gmrz.uaf.protocol.v1.schema.MatchCriteria;
import com.gmrz.uaf.protocol.v1.schema.Policy;
import com.gmrz.uaf.protocol.v1.schema.RegistrationRequest;
import com.gmrz.uaf.remote.plugin.AuthServicePluginManager;
import com.gmrz.uas.plugin.authservice.AuthServiceData;
import com.gmrz.uas.plugin.authservice.AuthServicePlugin;
import com.gmrz.uas.plugin.exception.PluginException;
import com.gmrz.util.Convert;
import com.gmrz.util.CryUtil;
import com.google.gson.Gson;
import com.google.inject.Inject;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by gongyuqiang on 2017/5/2.
 */
public class UAPRegInitProcessor extends UAFRegInitProcessor{

    private static final Logger LOG = LogManager.getLogger(UAFRegInitProcessor.class);

    AuthServicePluginManager serviceManager;

    @Inject
    public void setServiceManager(AuthServicePluginManager serviceManager) {
        this.serviceManager = serviceManager;
    }

    /**
     * 远程注册
     * @param plainUserName
     * @param hashUserName
     * @param appID
     * @param deviceID
     * @param authType
     * @param transType
     * @return
     * @throws PolicyNotFoundException
     * @throws DAOException
     */
    public List<RegistrationRequest> request(String plainUserName, String hashUserName, String appID, String deviceID,
                                             String authType, String transType,byte[] challengeParam,String dn)
            throws PolicyNotFoundException, DAOException {
        LOG.info("UAPRegInitProcess begin");
        RegistrationRequest request = GuiceUtil.getProcessorInjector()
                .getInstance(RegistrationRequest.class);

        Policy p = this.policyManager.getNamedPolicy(authType,appID,transType);
        LOG.info("Policy:" + UAFSchemaBuilder.getGson().toJson(p));
        if (p == null) {
            LOG.error("Requested policy {} is not available on server", "POLICY_"+appID+"_"+authType);
            throw new PolicyNotFoundException(UAFErrorCode.BIZ_POLICY_NOT_FOUND);
        }
        List<MatchCriteria> mcList = getMCListForAlreadyRegisteredNoDeviceId(hashUserName,appID,authType,transType);
        if (mcList != null) {
            p.appendDisallowed(mcList);
        }

        //MatchCriteria acceptedMatchCriteria = getAcceptedMatchCriteria(p);
        MatchCriteria acceptedMatchCriteria = null;
        List<List<MatchCriteria>> accepted = p.getAccepted();
        if(null != accepted && !accepted.isEmpty()){
            List<MatchCriteria> matchCriteriaAccepted = accepted.get(0);
            if(null != matchCriteriaAccepted && !matchCriteriaAccepted.isEmpty()){
               acceptedMatchCriteria = matchCriteriaAccepted.get(0);
            }
        }
        if(acceptedMatchCriteria != null){
            String pluginUserName = CryUtil.getSHA(hashUserName + "_" + appID + "_" + authType + "_" + transType);
            initAuthenticatorExts(acceptedMatchCriteria, authType, pluginUserName);
        }
        byte[] challenge = getRandom(32);
        challenge = ArrayUtils.addAll(challenge,challengeParam);
        request.getHeader().getServerData().withChallenge(challenge)
                .withPolicyName(p.getPolicyName()).withUserName(plainUserName);
        request.getHeader().setApplicationID(this.getServerConfig().getApplicationID(appID,transType));
        request.getChallenge().setChallenge(challenge);
        request.setPolicy(p);
        request.setUsername(hashUserName+"_"+authType+"_"+transType);
        if(serverConfig.getAppIdUrlBoolean(appID,transType)) {
            setFacetsAaid(request, appID);
        }
        List<RegistrationRequest> requests = new ArrayList<RegistrationRequest>();
        requests.add(request);
        LOG.info("UAPRegInitProcess end");
        return requests;
    }

    /**
     * 获取远程注册数据，例如：声纹数字
     * @param criteria
     * @param authType
     * @param pluginUserName
     */
    public void initAuthenticatorExts(MatchCriteria criteria, String authType, String pluginUserName) {
        try{
            String aaid = criteria.getAAID().get(0).toString();
            AuthServicePlugin service = serviceManager.getServicePlugin(aaid, authType);
            List<AuthServiceData> contents = service.pregregister(pluginUserName);
            if(contents != null && contents.size() > 0){
                List<Extension> exts = new ArrayList<Extension>();
                for(AuthServiceData content: contents){
                    Extension ext = new Extension();
                    ext.setId(content.getId());
                    ext.setData(Convert.toBase64(content.getContent()));
                    exts.add(ext);
                }
                criteria.setExtensions(exts);
            }
        }
        catch (PluginException e){
            LOG.error(e.getErrorMsg());
            throw new AuthenticationFailedException(e.getErrorMsg());
        }

    }
}
